在前面三天完成了:前端全日曆整合、 QR Code 簽到釋放以及 Telegram Bot 即時異動推播後,我們的 NGO 房間預約系統核心功能已全數到位。然而,在實際營運環境中,網路瞬斷、Google Sheet 讀寫失敗、Telegram API 額度限制或無效的輸入資料都可能引發未預期的異常(Exceptions)。
今天我們進入 模組 F:系統可靠性與自我診斷機制,開發全系統錯誤處理與 Log 紀錄模組——ErrorReportingService.gs。透過全域 Try-Catch 異常捕捉、Google Sheet 稽核日誌(Audit Log)與 Telegram 即時錯誤告警,打造產品級的強韌系統。
系統的錯誤監控與告警機制運作流程如下:
[前端/後端 API 執行] ──► [ Try-Catch 捕捉異常 ]
│
▼
[ ErrorReportingService.gs ]
│
┌──────────────────────┴──────────────────────┐
▼ ▼
[ 1. 寫入 "SystemLogs" Sheet ] [ 2. Telegram 即時發送錯誤告警 ]
(保留完整 StackTrace 與 Context) (即時通知技術管理員)
INFO(一般資訊)、WARNING(警告)與 CRITICAL(嚴重錯誤),避免告警疲勞。ErrorReportingService.gs)請在 Apps Script 專案中新增名為 ErrorReportingService.gs 的檔案,寫入以下程式碼:
/**
* ==============================================================================
* 全系統錯誤處理與 Log 日誌紀錄模組 (ErrorReportingService.gs)
* 專案:NGO 房間與資源預約管理系統 (Build on Google AI Track)
* 說明:提供統一的 Try-Catch 異常處理、Google Sheets 日誌備份與 Telegram 錯誤告警。
* ==============================================================================
*/
/**
* 錯誤嚴重程度枚舉
*/
const LOG_LEVEL = {
INFO: "INFO",
WARN: "WARNING",
ERROR: "ERROR",
CRITICAL: "CRITICAL"
};
/**
* 全域錯誤處理與日誌紀錄主函式
* @param {Error|string} error - 捕捉到的 Error 物件或錯誤字串
* @param {string} functionName - 發生錯誤的函式名稱
* @param {Object} [contextData] - 發生錯誤時的上下文參數 (可選)
* @param {string} [level=LOG_LEVEL.ERROR] - 嚴重程度
*/
function logAndReportError(error, functionName, contextData = {}, level = LOG_LEVEL.ERROR) {
const now = new Date();
const errorMessage = error.message || error.toString();
const stackTrace = error.stack || "無 Stack Trace";
const contextJson = JSON.stringify(contextData);
// 1. 輸出至 Apps Script 原生 Logger (方便線上除錯)
Logger.log(`[${level}][${functionName}] ${errorMessage}`);
// 2. 寫入 Google Sheets "SystemLogs" 工作表 (永久留存)
try {
writeLogToSheet({
timestamp: now,
level: level,
functionName: functionName,
message: errorMessage,
context: contextJson,
stackTrace: stackTrace
});
} catch (sheetError) {
Logger.log(`❌ 寫入 SystemLogs 工作表失敗: ${sheetError.toString()}`);
}
// 3. 若為 ERROR 或 CRITICAL 級別,即時發送 Telegram 告警
if (level === LOG_LEVEL.ERROR || level === LOG_LEVEL.CRITICAL) {
try {
sendTelegramErrorAlert(functionName, errorMessage, level, contextJson);
} catch (tgError) {
Logger.log(`❌ 發送 Telegram 錯誤告警失敗: ${tgError.toString()}`);
}
}
}
/**
* 將日誌寫入 Google Sheets 中的 SystemLogs 工作表
*/
function writeLogToSheet(logItem) {
const config = getConfig();
const ss = SpreadsheetApp.openById(config.SPREADSHEET_ID);
let sheet = ss.getSheetByName("SystemLogs");
// 若工作表不存在則自動創建並初始化表頭
if (!sheet) {
sheet = ss.insertSheet("SystemLogs");
sheet.appendRow(["Timestamp", "Level", "Function", "Message", "ContextData", "StackTrace"]);
sheet.getRange(1, 1, 1, 6).setFontWeight("bold").setBackground("#f1f5f9");
sheet.setFrozenRows(1);
}
sheet.appendRow([
Utilities.formatDate(logItem.timestamp, "GMT+8", "yyyy-MM-dd HH:mm:ss"),
logItem.level,
logItem.functionName,
logItem.message,
logItem.context,
logItem.stackTrace
]);
}
/**
* 發送即時 Telegram 系統錯誤告警訊息
*/
function sendTelegramErrorAlert(functionName, errorMessage, level, contextJson) {
const alertMsg =
`🚨 <b>【系統異常告警Notification】</b>\n` +
`--------------------------------------\n` +
`⚠️ <b>告警級別:</b><code>${level}</code>\n` +
`🛠️ <b>發生模組/函式:</b><code>${functionName}</code>\n` +
`💬 <b>錯誤訊息:</b>${errorMessage}\n` +
`📦 <b>相關 Context:</b><pre>${contextJson}</pre>\n` +
`⏰ <b>發生時間:</b>${Utilities.formatDate(new Date(), "GMT+8", "yyyy-MM-dd HH:mm:ss")}\n` +
`--------------------------------------\n` +
`<i>請技術管理員儘速排查系統日誌。</i>`;
// 呼叫 Day 23 的 Telegram 推播函式
sendTelegramNotification(alertMsg);
}
/**
* 包裝業務邏輯的安全執行器 (Higher-Order Function 概念)
* 用於統一捕捉任何後端 API 的非預期例外
*/
function safeExecute(fn, functionName, fallbackValue = { success: false, message: "系統繁忙中,請稍後再試。" }, contextData = {}) {
try {
return fn();
} catch (error) {
logAndReportError(error, functionName, contextData, LOG_LEVEL.ERROR);
return fallbackValue;
}
}
以下示範如何將 ErrorReportingService.gs 無縫嵌入之前的核心業務模組中:
BookingService.gs 中的 API 進入點/**
* 提交新預約的安全 API 進入點 (示範 ErrorReportingService 的整合)
*/
function submitNewBookingSafe(userEmail, roomId, startTimeIso, endTimeIso, purpose) {
const contextData = { userEmail, roomId, startTimeIso, endTimeIso, purpose };
return safeExecute(function() {
// 呼叫原本 Day 19 的預約邏輯
return submitNewBooking(userEmail, roomId, startTimeIso, endTimeIso, purpose);
}, "submitNewBookingSafe", { success: false, message: "預約處理失敗,技術團隊已收到告警通知。" }, contextData);
}
你可在 Apps Script 中執行以下模擬測試,驗證當系統發生未預期錯誤時,是否能正確寫入 SystemLogs 工作表並推播 Telegram 告警:
/**
* 錯誤監控模組單元測試
*/
function testErrorLoggingAndAlert() {
Logger.log("=== 開始錯誤監控測試 ===");
try {
// 故意觸發未定義變數之 ReferenceError
let result = undefinedVariable.doSomething();
} catch (error) {
logAndReportError(
error,
"testErrorLoggingAndAlert",
{ testCase: "模擬前端傳入無效 JSON", userId: "worker_01" },
LOG_LEVEL.ERROR
);
}
Logger.log("測試完成,請檢查 Google Sheets 中的 SystemLogs 工作表與 Telegram 告警訊息。");
}
今天我們完成了 全系統錯誤處理、例外監控與 Log 日誌紀錄。藉由將全域 Try-Catch、SystemLogs 稽核軌跡與 Telegram 即時告警結合,大幅提升了系統的魯棒性(Robustness)與維運效率。
明天繼續……